package com.petdog.common.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.net.SocketTimeoutException;

/**
 * 验证码服务
 * 用于发送和管理验证码
 */
@Service
public class VerificationCodeService {
    
    private static final Logger logger = LoggerFactory.getLogger(VerificationCodeService.class);
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    @Autowired
    private JavaMailSender mailSender;
    
    @Autowired
    private MailSendExceptionHandler mailExceptionHandler;
    
    @Value("${spring.mail.username}")
    private String fromEmail;
    
    private static final String CODE_PREFIX = "verification:code:";
    private static final String COOLDOWN_PREFIX = "verification:cooldown:";
    private static final String MAIL_SEND_RETRY_PREFIX = "verification:mail:retry:";
    private static final int MAX_RETRY_COUNT = 3; // 最大重试次数
    private static final long RETRY_INTERVAL_MS = 1000; // 重试间隔
    private static final Random RANDOM = new Random();
    
    /**
     * 生成6位数字验证码
     */
    public String generateCode() {
        return String.format("%06d", RANDOM.nextInt(1000000));
    }
    
    /**
     * 发送验证码邮件
     */
    public boolean sendVerificationCode(String email, String code, String type) {
        logger.debug("开始发送验证码邮件，邮箱: {}, 类型: {}", email, type);
        
        // 检查并增加重试计数
        String retryKey = MAIL_SEND_RETRY_PREFIX + email;
        int retryCount = 0;
        String retryCountStr = redisTemplate.opsForValue().get(retryKey);
        if (retryCountStr != null) {
            retryCount = Integer.parseInt(retryCountStr);
            if (retryCount >= MAX_RETRY_COUNT) {
                logger.warn("邮箱 {} 已达到最大重试次数 {}", email, MAX_RETRY_COUNT);
                return false;
            }
        }
        
        try {
            // 尝试发送邮件
            return attemptSendEmail(email, code, type);
        } catch (Exception e) {
            // 使用异常处理器处理异常
            boolean handled = mailExceptionHandler.handleException(e);
            
            if (!handled) {
                // 如果异常未处理，尝试重试策略
                retryCount++;
                redisTemplate.opsForValue().set(retryKey, String.valueOf(retryCount), 10, TimeUnit.MINUTES);
                logger.warn("邮件发送失败，准备重试 ({}/{}), 邮箱: {}", 
                        retryCount, MAX_RETRY_COUNT, email);
                
                // 如果未达到最大重试次数，执行重试
                if (retryCount <= MAX_RETRY_COUNT) {
                    try {
                        Thread.sleep(RETRY_INTERVAL_MS); // 等待一段时间后重试
                        return attemptSendEmail(email, code, type);
                    } catch (Exception ex) {
                        logger.error("重试发送邮件失败，邮箱: {}, 错误: {}", email, ex.getMessage());
                        return false;
                    }
                }
            }
            return false;
        } finally {
            // 无论成功失败，清除重试计数
            redisTemplate.delete(retryKey);
        }
    }
    
    /**
     * 尝试发送邮件的核心方法
     */
    private boolean attemptSendEmail(String email, String code, String type) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
        
        helper.setFrom(fromEmail);
        helper.setTo(email);
        
        String subject = getSubjectByType(type);
        String content = getContentByType(type, code);
        
        helper.setSubject(subject);
        helper.setText(content, true);
        
        mailSender.send(message);
        logger.info("验证码邮件发送成功，邮箱: {}, 类型: {}", email, type);
        return true;
    }
    
    /**
     * 存储验证码
     */
    public void storeCode(String email, String code, int expirationMinutes) {
        String key = CODE_PREFIX + email;
        redisTemplate.opsForValue().set(key, code, expirationMinutes, TimeUnit.MINUTES);
    }
    
    /**
     * 验证验证码
     */
    public boolean verifyCode(String email, String code) {
        String key = CODE_PREFIX + email;
        String storedCode = redisTemplate.opsForValue().get(key);
        return code.equals(storedCode);
    }
    
    /**
     * 删除验证码
     */
    public void deleteCode(String email) {
        String key = CODE_PREFIX + email;
        redisTemplate.delete(key);
    }
    
    /**
     * 设置发送冷却期
     */
    public void setCooldown(String email, int seconds) {
        String key = COOLDOWN_PREFIX + email;
        redisTemplate.opsForValue().set(key, "", seconds, TimeUnit.SECONDS);
    }
    
    /**
     * 检查是否在冷却期
     */
    public boolean isInCooldown(String email) {
        String key = COOLDOWN_PREFIX + email;
        return redisTemplate.hasKey(key);
    }
    
    /**
     * 获取冷却期剩余时间
     */
    public long getCooldownRemainingTime(String email) {
        String key = COOLDOWN_PREFIX + email;
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }
    
    private String getSubjectByType(String type) {
        switch (type) {
            case "register":
                return "宠物狗平台 - 注册验证码";
            case "login":
                return "宠物狗平台 - 登录验证码";
            case "reset":
                return "宠物狗平台 - 密码重置验证码";
            default:
                return "宠物狗平台 - 验证码";
        }
    }
    
    private String getContentByType(String type, String code) {
        String action = "";
        switch (type) {
            case "register":
                action = "注册";
                break;
            case "login":
                action = "登录";
                break;
            case "reset":
                action = "密码重置";
                break;
            default:
                action = "验证";
        }
        
        return String.format(
            "<html><body>" +
            "<h2>宠物狗平台验证码</h2>" +
            "<p>您的%s验证码是：<strong style='color: #007bff; font-size: 24px;'>%s</strong></p>" +
            "<p>验证码有效期为10分钟，请及时使用。</p>" +
            "<p>如果这不是您的操作，请忽略此邮件。</p>" +
            "</body></html>",
            action, code
        );
    }
    
    /**
     * 生成并获取测试验证码（用于开发环境测试）
     * @param email 邮箱地址
     * @return 测试用的验证码
     */
    public String generateAndGetTestVerificationCode(String email) {
        String code = generateCode();
        storeCode(email, code, 10); // 存储10分钟
        logger.info("生成测试验证码: {} 对应邮箱: {}", code, email);
        return code;
    }
}


